home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
- **
- ** Project Name: DropShell
- ** File Name: DSUserProcs.c
- **
- ** Description: Specific AppleEvent handlers used by the DropBox
- **
- *******************************************************************************
- ** A U T H O R I D E N T I T Y
- *******************************************************************************
- **
- ** Initials Name
- ** -------- -----------------------------------------------
- ** LDR Leonard Rosenthol
- ** MTC Marshall Clow
- ** SCS Stephan Somogyi
- **
- *******************************************************************************
- ** R E V I S I O N H I S T O R Y
- *******************************************************************************
- **
- ** Date Time Author Description
- ** -------- ----- ------ ---------------------------------------------
- ** 06/23/94 LDR Added support for ProcessItem and ProcessFolder handling
- ** 02/20/94 LDR Modified Preflight & Postflight to take item count
- ** 01/25/92 LDR Removed the use of const on the userDataHandle
- ** 12/09/91 LDR Added the new SelectFile userProc
- ** Added the new Install & DisposeUserGlobals procs
- ** Modified PostFlight to only autoquit on odoc, not pdoc
- ** 11/24/91 LDR Added the userProcs for pdoc handler
- ** Cleaned up the placement of braces
- ** Added the passing of a userDataHandle
- ** 10/29/91 SCS Changes for THINK C 5
- ** 10/28/91 LDR Officially renamed DropShell (from QuickShell)
- ** Added a bunch of comments for clarification
- ** 10/06/91 00:02 MTC Converted to MPW C
- ** 04/09/91 00:02 LDR Added to Projector
- **
- ******************************************************************************/
-
- #include <StandardFile.h>
-
- #include "DSGlobals.h"
- #include "DSUserProcs.h"
-
- // Static Prototypes
- static OSErr ProcessItem(FSSpecPtr myFSSPtr);
- static OSErr ReverseProcessItem(FSSpecPtr myFSSPtr);
- static OSErr AddRegistrationInfo(FSSpecPtr myFSSPtr);
- static OSErr ProcessFolder(FSSpecPtr myFSSPtr);
- static OSErr UpdateCFRG(short resRef,Byte fragmentType, Byte fragmentLocation,
- long fragmentOffset, long fragmentLength);
- static short isPressed(unsigned short key );
-
- extern void DoUpdate(EventRecord *event);
-
- Handle gMessage;
-
- /*
- Uncomment this line if you want each item of a dropped folder processed
- as an individual item
- */
- // #define qWalkFolders
-
-
- /*
- This routine is called during init time.
-
- It allows you to install more AEVT Handlers beyond the standard four
- */
- #pragma segment Main
- pascal void InstallOtherEvents (void) {
- }
-
-
- /*
- This routine is called when an OAPP event is received.
-
- Currently, all it does is set the gOApped flag, so you know that
- you were called initally with no docs, and therefore you shouldn't
- quit when done processing any following odocs.
- */
- #pragma segment Main
- pascal void OpenApp (void)
- {
- gOApped = true;
- DoUpdate(&gEvent);
- }
-
-
- /*
- This routine is called when an QUIT event is received.
-
- We simply set the global done flag so that the main event loop can
- gracefully exit. We DO NOT call ExitToShell for two reasons:
- 1) It is a pretty ugly thing to do, but more importantly
- 2) The Apple event manager will get REAL upset!
- */
- #pragma segment Main
- pascal void QuitApp (void) {
- gDone = true; /* All Done! */
- }
-
-
- /*
- This routine is the first one called when an ODOC or PDOC event is received.
-
- In this routine you would place code used to setup structures, etc.
- which would be used in a 'for all docs' situation (like "Archive all
- dropped files")
-
- Obviously, the opening boolean tells you whether you should be opening
- or printing these files based on the type of event recieved.
-
- NEW IN 2.0!
- The itemCount parameter is simply the number of items that were dropped on
- the application and that you will be processing. This gives you the ability
- to do a single preflight for memory allocation needs, rather than doing it
- once for each item as in previous versions.
-
- userDataHandle is a handle that you can create & use to store your own
- data structs. This dataHandle will be passed around to the other
- odoc/pdoc routines so that you can get at your data without using
- globals - just like the new StandardFile.
-
- We also return a boolean to tell the caller if you support this type
- of event. By default, our dropboxes don't support the pdoc, so when
- opening is FALSE, we return FALSE to let the caller send back the
- proper error code to the AEManager.
-
- */
- #pragma segment Main
- pascal Boolean PreFlightDocs (Boolean opening, short itemCount, Handle *userDataHandle)
- {
-
- if (isPressed(kControlKeyScanCode))
- gAddRegistrationInfoOnly = true;
-
- if (isPressed(kOptionKeyScanCode))
- gReverseOperation = true;
- else
- gReverseOperation = false;
-
- return opening; // we support opening, but not printing - see above
- }
-
-
- /*
- This routine is called for each file passed in the ODOC event.
-
- In this routine you would place code for processing each file/folder/disk that
- was dropped on top of you.
-
- You will probably want to remove the #pragma unused (currently there to fool the compiler!)
- */
- #pragma segment Main
- pascal void OpenDoc ( FSSpecPtr myFSSPtr, Boolean opening, Handle userDataHandle ) {
- #pragma unused ( myFSSPtr )
- #pragma unused ( opening )
- #pragma unused ( userDataHandle )
- OSErr err = noErr;
-
-
- #ifdef qWalkFolders
- /*
- For this case we need to determine if the FSSpec is a file or folder.
- If it's a folder, we then need to process each item in that folder,
- otherwise just process the item.
- */
- if (FSpIsFolder(myFSSPtr))
- err = ProcessFolder(myFSSPtr);
- else
- err = ProcessItem(myFSSPtr);
- #else
- /*
- For this case we just call ProcessItem on the FSSpec above.
- */
- err = ProcessItem(myFSSPtr);
- #endif
-
- // you should probably do something if you get back an error ;)
- }
-
-
- /*
- This routine is the last routine called as part of an ODOC event.
-
- In this routine you would place code to process any structures, etc.
- that you setup in the PreflightDocs routine.
-
- NEW IN 2.0!
- The itemCount parameter was the number of items that you processed.
- It is passed here just in case you need it ;)
-
- If you created a userDataHandle in the PreFlightDocs routines, this is
- the place to dispose of it since the Shell will NOT do it for you!
-
- You will probably want to remove the #pragma unusued (currently there to fool the compiler!)
- */
- #pragma segment Main
- pascal void PostFlightDocs ( Boolean opening, short itemCount, Handle userDataHandle ) {
- #pragma unused ( opening )
- #pragma unused ( itemCount )
- #pragma unused ( userDataHandle )
-
- if ( (opening) && (!gOApped) )
- gDone = true; // close everything up!
-
- /*
- The reason we do not auto quit is based on a recommendation in the
- Apple event Registry which specifically states that you should NOT
- quit on a 'pdoc' as the Finder will send you a 'quit' when it is
- ready for you to do so.
- */
- }
-
-
-
- static OSErr UpdateCFRG(short resRef,Byte fragmentType, Byte fragmentLocation,
- long fragmentOffset, long fragmentLength)
- {
- codeFragRecHandle cfrgHndl;
- codeFragRecPtr cfrgRecPtr;
-
- OSErr theError = -1;
-
- cfrgHndl = (codeFragRecHandle) Get1Resource('cfrg',0);
-
- if (cfrgHndl != NULL)
- {
- HLock((Handle) cfrgHndl);
- (**cfrgHndl).fragArray[0].TypeOfFrag = fragmentType;
- (**cfrgHndl).fragArray[0].LocationOfFrag = fragmentLocation;
-
- (**cfrgHndl).fragArray[0].OffsetToFrag = fragmentOffset;
- (**cfrgHndl).fragArray[0].LengthOfFrag = fragmentLength;
-
- // (**cfrgHndl).fragArray[0].OffsetToFrag = kPowerPCCode;
- // (**cfrgHndl).fragArray[0].LengthOfFrag = kPowerPCID;
-
- HUnlock((Handle) cfrgHndl);
- ChangedResource((Handle) cfrgHndl);
- UpdateResFile(resRef);
- ReleaseResource((Handle) cfrgHndl);
- return noErr;
-
- }
- return theError;
- }
-
- //A simple utility to check if a particular key is pressed
- //key is any keyboard scan code 0 -127
- static short isPressed(unsigned short key )
- {
- unsigned char km[16];
-
- GetKeys( (unsigned long *) km); //rs Note universal headers 2.1 changed this to unsigned
- return ( ( km[key>>3] >> (key & 7) ) & 1);
- }
-
-
- /*
- This routine gets called for each item (which could be either a file or a folder)
- that the caller wants dropped. The determining factor is the definition of the
- qWalkFolder compiler directive. Either way, the item in question should be
- processed as a single item and not "dissected" into component units (like subfiles
- of a folder!)
- */
- static OSErr ProcessItem(FSSpecPtr myFSSPtr)
- {
- OSErr err = noErr;
- short refNum;
- short resRef;
- long logEOF;
- long count;
- Handle POWER_PC_CODE;
- short resultCode;
- short itemHit;
-
-
- if (gAddRegistrationInfoOnly)
- {
- return(AddRegistrationInfo(myFSSPtr));
- }
-
- if (gReverseOperation)
- {
- return(ReverseProcessItem(myFSSPtr));
- }
-
- err = FSpOpenDF(myFSSPtr, fsRdWrPerm, &refNum); //Open the Data fork containing the
- if (err == noErr) //PowerPC code.
- {
- resRef = FSpOpenResFile(myFSSPtr,fsRdWrPerm); //Open the Resource fork as
- if (resRef != -1) //we will adding a new resource to hold the powerPC code
- {
- err = GetEOF(refNum,&logEOF);
- if (logEOF == 0)
- {
- itemHit = Alert(kNoDataFork,nil);
- }
- else
- {
- if (logEOF < kMaxResourceSize) //Check to see we don't exceed the max resource size
- { //as Power PC Applications can be very large
- POWER_PC_CODE = Get1Resource(kPowerPCCode,kPowerPCID);
- if (POWER_PC_CODE != NULL)
- {
- RemoveResource(POWER_PC_CODE); //remove PowerPc code in resource if it already exists
- UpdateResFile(resRef); //update resource
- }
-
- POWER_PC_CODE = NewHandle(logEOF); //allocate a buffer
-
- if (POWER_PC_CODE == NULL)
- POWER_PC_CODE = TempNewHandle(logEOF,&resultCode); //Use system memory if possible
- //this way you don't have to worry about
- if (POWER_PC_CODE != NULL) //setting an appropiate 'size' resource
- {
- count = logEOF;
- err = FSRead(refNum,&count,*POWER_PC_CODE);
- AddResource(POWER_PC_CODE,kPowerPCCode,kPowerPCID,"\pPPC Code");
- WriteResource(POWER_PC_CODE);
- UpdateResFile(resRef);
- ReleaseResource(POWER_PC_CODE);
- err = SetEOF(refNum,0); //set the data fork to 0;
- err = UpdateCFRG(resRef,kUsageIsApplication,kFragmentInResource,kPowerPCCode,kPowerPCID);//update 'cfrg' resource to point to right location
- }
- else
- itemHit = Alert(kMemErrorID,NULL);
- }
- else
- itemHit = Alert(kTooBigID,NULL);
- }
- }
- err = FSClose(refNum);
- }
- else
- itemHit = Alert(kDataForkError,NULL);
-
- return(err);
- }
-
-
- /*
- Depending on whether the user held down the option key on application startup
- This routine gets called for each item (which could be either a file or a folder)
- that the caller wants dropped. The determining factor is the definition of the
- qWalkFolder compiler directive. Either way, the item in question should be
- processed as a single item and not "dissected" into component units (like subfiles
- of a folder!)
-
- */
- static OSErr ReverseProcessItem(FSSpecPtr myFSSPtr)
- {
- OSErr err = noErr;
- short refNum;
- short resRef;
- long logEOF;
- long count;
- Handle POWER_PC_CODE;
- short resultCode;
- short itemHit;
-
- err = FSpOpenDF(myFSSPtr, fsRdWrPerm, &refNum); //Open the Data fork containing the
- if (err == noErr) //PowerPC code.
- {
- resRef = FSpOpenResFile(myFSSPtr,fsRdWrPerm); //Open the Resource fork as
- if (resRef != -1) //we will adding a new resource to hold the powerPC code
- {
- err = GetEOF(refNum,&logEOF);
- if (logEOF != 0)
- {
- itemHit = Alert(kDataForkError,nil);
- }
- else
- {
- POWER_PC_CODE = Get1Resource(kPowerPCCode,kPowerPCID);
- logEOF = GetHandleSize(POWER_PC_CODE);
-
- if (POWER_PC_CODE != NULL)
- {
- RemoveResource(POWER_PC_CODE); //remove PowerPc code in resource if it already exists
- UpdateResFile(resRef); //update resource
- }
-
- if (POWER_PC_CODE != NULL)
- {
- count = logEOF;
- err = FSWrite(refNum,&count,*POWER_PC_CODE);
- ReleaseResource(POWER_PC_CODE);
- err = UpdateCFRG(resRef,kUsageIsApplication,kFragmentInDataFork,kBeginningOfFragment,kWholeFork); //update 'cfrg' resource to point to right location
- }
- else
- itemHit = Alert(kMemErrorID,NULL);
- }
- }
- }
- else
- itemHit = Alert(kDataForkError,NULL);
-
- err = FSClose(refNum);
- return(err);
- }
-
-
- static OSErr AddRegistrationInfo(FSSpecPtr myFSSPtr)
- {
- OSErr err = noErr;
- short refNum;
- short resRef;
- long logEOF;
- long count;
- Handle POWER_PC_CODE;
- short resultCode;
- short itemHit;
-
- ProductRegistrationInfo theData = {'DATA',911,TRUE,'X',"\p",'END'};
- long infoSize = sizeof(theData);
-
- err = FSpOpenDF(myFSSPtr, fsRdWrPerm, &refNum); //Open the Data fork containing the
-
- if (err == noErr) //PowerPC code.
- {
- err = GetEOF(refNum,&logEOF);
- if (logEOF == 0)
- {
- itemHit = Alert(kNoDataFork,nil);
- }
- else
- {
- POWER_PC_CODE = NewHandle(logEOF); //allocate a buffer
-
- if (POWER_PC_CODE == NULL)
- POWER_PC_CODE = TempNewHandle(logEOF,&resultCode); //Use system memory if possible
- //this way you don't have to worry about
- if (POWER_PC_CODE != NULL) //setting an appropiate 'size' resource
- {
- resRef = FSpOpenResFile(myFSSPtr,fsRdWrPerm); //Open the Resource fork as
- if (resRef != -1)
- {
- count = logEOF;
- err = FSRead(refNum,&count,*POWER_PC_CODE); //Read the PPC code
- err = SetFPos(refNum,fsFromStart,0); //Reset the file mark to the beginning of the file
- PLstrcpy(theData.subliminalMessage,"\pThis Data Located before Start of PPC code fragment. ");
- err = FSWrite(refNum,&infoSize,&theData); //Write my custom Data at the beginning of the file
- err = FSWrite(refNum,&count,*POWER_PC_CODE); //Write out the PPC code
- PLstrcpy(theData.subliminalMessage,"\pThis Data after the Main PPC code fragment. ");
- err = FSWrite(refNum,&infoSize,&theData); //Write my custom Data again at the end of the file
- err = UpdateCFRG(resRef,kUsageIsApplication,kOnDiskFlat,infoSize,kWholeFork);//update 'cfrg' resource to point to right location
- UpdateResFile(resRef);
- }
- }
- else
- itemHit = Alert(kMemErrorID,NULL);
- }
- }
-
- err = FSClose(refNum);
- return(err);
- }
-
- /*
- This routine gets called for any folder (or disk) that the caller wants
- processed as a set of component items, instead of as a single entity.
- The determining factor is the definition of the qWalkFolder compiler directive.
- */
- static OSErr ProcessFolder(FSSpecPtr myFSSPtr)
- {
- OSErr err = noErr;
- short index, oldIndex, localIndex;
- FSSpec localFSSpec, curFSSpec;
- CInfoPBRec cipb;
- Str255 fName, vFName;
- long dirID, origDirID;
- Boolean foundPosition;
-
- // copy the source locally to avoid recursion problems
- BlockMoveData(myFSSPtr, &localFSSpec, sizeof(FSSpec));
-
- // get the dirID for THIS folder, not it's parent!
- BlockMoveData(localFSSpec.name, fName, 32);
-
- cipb.hFileInfo.ioCompletion = 0L;
- cipb.hFileInfo.ioNamePtr = fName;
- cipb.hFileInfo.ioVRefNum = localFSSpec.vRefNum;
- cipb.hFileInfo.ioFDirIndex = 0; // use the dir & vRefNum;
- cipb.hFileInfo.ioDirID = localFSSpec.parID;
- err = PBGetCatInfoSync(&cipb);
-
- if (!err) {
- origDirID = cipb.dirInfo.ioDrDirID; // copy the sucker
- index = 1;
-
- // index through all contents of this folder
- while (err == noErr) {
- dirID = origDirID;
- localIndex = index;
- fName [0] = 0;
- cipb.hFileInfo.ioCompletion = 0L;
- cipb.hFileInfo.ioNamePtr = fName;
- cipb.hFileInfo.ioVRefNum = localFSSpec.vRefNum;
- cipb.hFileInfo.ioFDirIndex = localIndex; // use a real index
- cipb.hFileInfo.ioDirID = dirID;
- err = PBGetCatInfoSync(&cipb);
-
- if (!err) {
- BlockMoveData(fName, curFSSpec.name, 32);
- curFSSpec.vRefNum = cipb.hFileInfo.ioVRefNum;
- curFSSpec.parID = dirID;
-
- /*
- Check to see if this entry is a folder.
- */
- if (cipb.hFileInfo.ioFlAttrib & ioDirMask) {
- err = ProcessFolder(&curFSSpec);
- } else
- err = ProcessItem(&curFSSpec);
-
- /* If we've had an error, get out! */
- if (err) break;
-
- // dirID = origDirID;
- localIndex = index;
-
- /*
- Now take into account new files being created
- in the current directory & messing up our index.
- See Dev.CD Vol. XI:Tools & Apps (Moof!):Misc Utilities:
- Disinfectant & Source 2.5.1:Sample:Notes:Scan Alg
- */
- vFName [0] = 0;
- cipb.hFileInfo.ioCompletion = 0L;
- cipb.hFileInfo.ioNamePtr = vFName;
- cipb.hFileInfo.ioVRefNum = localFSSpec.vRefNum;
- cipb.hFileInfo.ioFDirIndex = localIndex; // use a real index
- cipb.hFileInfo.ioDirID = dirID;
- err = PBGetCatInfoSync(&cipb);
- oldIndex = index;
- if (!err) {
- /* If they're equal - same place, go to next */
- if (EqualString (vFName, fName, false, false))
- index++;
- }
-
- /* If we didn't advance, then perhaps a file was created or deleted */
- if (oldIndex == index) {
- oldIndex = index; /* save off the old */
- index = 0; /* and start at the beginning */
- err = noErr;
- vFName [0] = 0;
- foundPosition = false;
-
- while (!foundPosition) {
- index++;
- vFName [0] = 0;
- cipb.hFileInfo.ioCompletion = 0L;
- cipb.hFileInfo.ioNamePtr = vFName;
- cipb.hFileInfo.ioVRefNum = localFSSpec.vRefNum;
- cipb.hFileInfo.ioFDirIndex = index; /* now use a real index */
- cipb.hFileInfo.ioDirID = dirID;
- err = PBGetCatInfoSync(&cipb);
-
- if (err == fnfErr) { // we've just been deleted
- index = oldIndex;
- foundPosition = true;
- err = noErr; // have to remember to reset this!
- }
-
- /* found same file & same index position */
- /* so try the next item */
- if ((!foundPosition) && EqualString(fName, vFName, false, false)) {
- index++;
- foundPosition = true;
- }
- }
- }
- }
- }
- }
-
- return(err);
- }
-
- /*
- This routine is called when the user chooses "Select File…" from the
- File Menu.
-
- Currently it simply calls the new StandardGetFile routine to have the
- user select a single file (any type, numTypes = -1) and then calls the
- SendODOCToSelf routine in order to process it.
-
- The reason we send an odoc to ourselves is two fold: 1) it keeps the code
- cleaner as all file openings go through the same process, and 2) if events
- are ever recordable, the right things happen (this is called Factoring!)
-
- Modification of this routine to only select certain types of files, selection
- of multiple files, and/or handling of folder & disk selection is left
- as an exercise to the reader.
- */
- pascal void SelectFile (void)
- {
- StandardFileReply stdReply;
- SFTypeList theTypeList;
-
- StandardGetFile(NULL, -1, theTypeList, &stdReply);
- if (stdReply.sfGood) // user did not cancel
- SendODOCToSelf(&stdReply.sfFile); // so send me an event!
- }
-
- /*
- This routine is called during the program's initialization and gives you
- a chance to allocate or initialize any of your own globals that your
- dropbox needs.
-
- You return a boolean value which determines if you were successful.
- Returning false will cause DropShell to exit immediately.
- */
- pascal Boolean InitUserGlobals(void)
- {
- gMessage = GetResource('TEXT',128);
- return(true); // nothing to do, it we must be successful!
- }
-
- /*
- This routine is called during the program's cleanup and gives you
- a chance to deallocate any of your own globals that you allocated
- in the above routine.
- */
- pascal void DisposeUserGlobals(void)
- {
- // nothing to do for our sample dropbox
- }
-